<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ajax原生请求</title>
</head>
<body>
    <button>1.GET请求</button>
    <button>2.POST请求</button>
    <button>3.设置请求参数</button>
    <button>4.设置请求头和请求体</button>
    <p></p>
    <button>5.接收响应体为json格式</button>
    <button>6.请求超时和网络异常</button>
    <button>7.解决IE缓存问题</button>
    <p></p>    
    <p>测试效果：先点发送，立即点取消，取消的请求，network中状态为cancelled</p>
    <button>8.点击发送请求</button>
    <button>9.点击取消请求</button>
    <p></p>
    <p>测试效果：重复点发送按钮，一直点一直点，发现上一个请求未完成时，就取消上一个</p>
    <button>10.重复发送问题</button>
    <p></p>
    <button>11.fetch发送ajax请求</button>
    <p></p>
    <button>12.jsonp方法解决跨域</button>
    <button>13.cors方法解决跨域</button>
    <p></p>


    <script>
        // 注意看【请求报文】 和 【响应报文】
        // 请求报文：请求行、请求头、请求体
        // 响应报文：响应行、响应头、响应体

        let btns = document.querySelectorAll('button')
        // 1.发送get请求
        btns[0].onclick = function(){
            // 创建对象
            let xhr = new XMLHttpRequest()
            // 初始化请求
            xhr.open('GET', 'http://127.0.0.1:8000/getRequest')
            // 发送请求
            xhr.send()
            // 监听状态改变事件
            xhr.onreadystatechange = function() {
                // 请求完成
                if(xhr.readyState === 4) {
                    // 请求成功
                    if(xhr.status>=200 && xhr.status<300){
                        console.log('get请求响应体', xhr.response)
                    }
                }
            }
        }
        // 2.发送post请求
        btns[1].onclick = function(){
            let xhr = new XMLHttpRequest()
            xhr.open('POST', 'http://127.0.0.1:8000/postRequest')
            xhr.send()
            xhr.onreadystatechange = function() {
                if(xhr.readyState === 4) {
                    if(xhr.status>=200 && xhr.status<300){
                        console.log('post请求响应体', xhr.response)
                    }
                }
            }
        }
        // 3.设置请求参数
        btns[2].onclick = function(){
            let xhr = new XMLHttpRequest()
            // 设置url参数，直接在URL后面拼接，以这个形式?a=100&b=100
            xhr.open('GET', 'http://127.0.0.1:8000/getRequest?a=100&b=100')            
            xhr.send()
            xhr.onreadystatechange = function() {
                if(xhr.readyState === 4) {
                    if(xhr.status>=200 && xhr.status<300){
                        console.log('设置url参数', xhr.response)
                    }
                }
            }
        }
        // 4.设置请求头和请求体
        btns[3].onclick = function(){
            let xhr = new XMLHttpRequest()
            xhr.open('POST', 'http://127.0.0.1:8000/set')      
            // 设置请求头
            // 预定义请求头名
            xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
            // 自定义请求头名，需要服务端设置允许请求头的配置
            xhr.setRequestHeader('name', '123123') // Safari浏览器巨坑！自定义请求头设置一直报错
            // 设置请求体，可以是任意格式，服务端要有与之对应的处理方式就行
            xhr.send('a=100&b=100')
            // xhr.send('a:100&b:100')
            // xhr.send('1234567')
            xhr.onreadystatechange = function() {
                if(xhr.readyState === 4) {
                    if(xhr.status>=200 && xhr.status<300){
                        console.log('设置请求头和请求体', xhr.response)
                    }
                }
            }
        }
        // 5.接收json格式的响应体
        btns[4].onclick = function(){
            let xhr = new XMLHttpRequest()
            // 设置响应体类型，会自动转换
            xhr.responseType = 'json'
            xhr.open('POST', 'http://127.0.0.1:8000/jsonServer')            
            xhr.send()
            xhr.onreadystatechange = function() {
                if(xhr.readyState === 4) {
                    if(xhr.status>=200 && xhr.status<300){
                        // 手动解析JSON格式响应体
                        // console.log('post请求响应体', JSON.parse(xhr.response))
                        console.log('post请求响应体', xhr.response)
                    }
                }
            }
        }

        // 6.请求超时和网络异常
        btns[5].onclick = function(){
            const xhr = new XMLHttpRequest()
            // 超时会自动取消请求
            xhr.timeout = 2000
            // 超时回调
            xhr.ontimeout = function () {
                alert('网络异常，请稍后重试哦！')
            }
            // 网络异常回调
            xhr.onerror = function() {
                alert('您的网络似乎出了一些问题！')
            }
            xhr.open('GET', 'http://127.0.0.1:8000/delay')
            xhr.send()
            xhr.onreadystatechange = function(){
                if(xhr.readyState === 4) {
                    if(xhr.status >=200 && xhr.status < 300) {
                        console.log(xhr.response)
                    }
                }
            }
            
        }

        // 7.解决缓存 
        // IE浏览器会走缓存，测试：响应体更改保存，浏览器去获取，还是上一次的结果，不是最新的结果
        btns[6].onclick = function() {
            const xhr = new XMLHttpRequest()
            // 解决：加一个时间戳参数，每次URL都不一样，就不会走缓存
            xhr.open('GET', 'http://127.0.0.1:8000/catch?time='+Date.now())
            xhr.send()
            xhr.onreadystatechange = function() {
                if(xhr.readyState === 4) {
                    if(xhr.status >=200 && xhr.status < 300) {
                        console.log(xhr.response)
                    }
                }
            }
        }

        // 8.9.手动取消请求
        let xhr = null
        btns[7].onclick = function() {
            xhr = new XMLHttpRequest()
            xhr.open('GET', 'http://127.0.0.1:8000/delay')
            xhr.send()
        }
        btns[8].onclick = function() {
            xhr.abort()
        }

        // 10.重复发送问题，自动取消请求
        let xhr2 = null
        let isSendFinished = true // 是否发送完成
        btns[9].onclick = function() {
            // 如果发送未完成，取消请求，创建一个新请求
            if(!isSendFinished){
                xhr2.abort()
            }
            xhr2 = new XMLHttpRequest()
            isSendFinished = false
            xhr2.open('GET', 'http://127.0.0.1:8000/delay')
            xhr2.send()
            xhr2.onreadystatechange = function(){
                if(xhr2.readyState===4){
                    isSendFinished = true
                    if(xhr2.status >= 200 && xhr2.status < 300){
                        console.log('成功了', xhr2.response)
                    }
                }
            }
        }

        // 11.fetch发送ajax请求
        btns[10].onclick = function() {
            fetch('http://127.0.0.1:8000/fetchServer', {
                // 请求方式
                method: 'POST',
                // 请求头
                headers: {
                    name: 'beauty',                    
                },
                //请求体
                body: '000'
            }).then(res => {
                return res.text()
            }).then(res => {
                console.log(res)
            }).catch(err =>{
                console.log(err)
            })
        }

        // 同源策略：协议、域名、端口 要一致
        // ajax是遵循同源策略的
        // 跨域解决方案
        /* 
            1. jsonp方法
                因为html有些标签自带跨越，比如img/link/script，
                jsonp核心就是，利用script标签自带跨域的特性去实现。
                只适用于get请求方式       
            2. cors方法
                服务端实现，设置响应头，将“Access-Control-Allow-Origin”设置为*，允许任意地址跨域请求。 
                也可以设置某几个地址跨域
        */

        
        // 12.jsonp方法跨域
        // 本质是利用script获取一段js代码，js引擎会执行它
        /* 核心要点就是：
            1. 给script标签scr属性的值设置为请求路径，在请求URL中传一个参数给服务端，
               参数名随意，比如叫callback，参数值为一个事先准备好的函数名，这个函数的作用就是接收到响应体时做相应的处理的
            2. 服务端在返回响应体时，要以“函数名(响应体数据)”的形式来返回，那么script标签接收的内容就是这个方法调用的js代码，
                js引擎解析后会自动执行这个函数，而响应体数据就在函数的形参中获得了，再做相应处理就可以了
        */           
        btns[11].onclick = function(){
            let script = document.createElement('script')            
            script.src = `http://127.0.0.1:8000/jsonpServer?callback=handle`
            document.getElementsByTagName('body')[0].append(script)
        }
        // 接收响应体
        function handle(data){
            console.log(data)
        }
       
        // 13.cors解决跨域问题
        // 官方解决手段
        /* 服务端做设置，不需要前端做处理。
            主要就是通过设置“Access-Control-Allow-Origin”这个字段，访问控制允许源，
            可以指定允许哪些来源访问你，也可以直接设置通配符“*”，允许任意来源访问。
        */
       btns[12].onclick = function() {
           const xhr = new XMLHttpRequest()
           xhr.open('post', 'http://127.0.0.1:8000/cors')
           xhr.send()
           xhr.onreadystatechange = function() {
               if(xhr.readyState === 4) {
                   if(xhr.status >= 200 && xhr.status <300){
                       console.log('success', xhr.response)
                   }
               }
           }
       }

    </script>
</body>
</html>